package com.tfswx.fljdmxyy.utils.sm4;

import lombok.Getter;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class DecryptSm4InputStream extends DecorateInputStreamBase {

    private static final InnerSM4_Context SM4_CONTEXT_DECRYPT = new InnerSM4_Context(InnerSM4Stream.SM4_DECRYPT);
    private final byte[] iv = new byte[16];
    private final byte[] beforeBuffer = new byte[16];
    private final byte[] out = new byte[16];
    private final byte[] temp = new byte[16];
    @Getter
    private String name = "[null]";
    private volatile int beforeLength;
    private volatile boolean isEnd;
    public DecryptSm4InputStream(InputStream in) {
        super(in, 16, 16);
    }
    public DecryptSm4InputStream(String name, InputStream in) {
        this(in);
        this.name = name;
    }
    public DecryptSm4InputStream(byte[] encryptData) {
        this(createInputStream(encryptData));
    }
    public DecryptSm4InputStream(String name, byte[] encryptData) {
        this(encryptData);

        this.name = name;
    }

    private static InputStream createInputStream(byte[] encryptData) {
        if (encryptData == null || encryptData.length == 0) {
            throw new IllegalArgumentException("encryptData 不能为空");
        }
        if ((encryptData.length < 16) || (encryptData.length % 16 != 0)) {
            throw new IllegalArgumentException("encryptData 不是有效的SM4加密文件");
        }

        return new ByteArrayInputStream(encryptData);
    }

    @Override
    protected int innerReadTo(byte[] sourceBuffer, int sourceBufferLength, byte[] destBuffer) {

        if (isEnd) {
            return -1;
        }

        if (sourceBufferLength == 16) {
            // 处理之前段
            System.arraycopy(beforeBuffer, 0, temp, 0, 16);
            InnerSM4Stream.sm4_one_round(SM4_CONTEXT_DECRYPT.sk, beforeBuffer, out);
            for (int i = 0; i < 16; i++) {
                destBuffer[i] = ((byte) (out[i] ^ iv[i]));
            }
            System.arraycopy(temp, 0, iv, 0, 16);
            // 保存当前段
            System.arraycopy(sourceBuffer, 0, beforeBuffer, 0, 16);
//            beforeLength = 16;
            return 16;
        } else if (sourceBufferLength <= 0) {
            // 上一段是最后一段
            isEnd = true;
            // 处理之前段
            System.arraycopy(beforeBuffer, 0, temp, 0, 16);
            InnerSM4Stream.sm4_one_round(SM4_CONTEXT_DECRYPT.sk, beforeBuffer, out);
            for (int i = 0; i < 16; i++) {
                destBuffer[i] = ((byte) (out[i] ^ iv[i]));
            }

            int paddingCount = destBuffer[destBuffer.length - 1];
            int beforeTrueLength = 16 - paddingCount;
            if (0 < beforeTrueLength && beforeTrueLength < 16) {
                return beforeTrueLength;
            } else if (beforeTrueLength == 0) {
                return -1;
            } else if (beforeTrueLength == 16) {
                // 错误数据，兼容处理
//                log.error("（兼容处理，错误已忽略）文件数据异常，不是有效的SM4加密文件：{}b；file：{}", beforeTrueLength, name);
                return 16;
            } else {
//                throw new RuntimeException("文件数据异常，不是有效的SM4加密文件");
//                log.error("（兼容处理，错误已忽略）文件数据异常，不是有效的SM4加密文件：{}b；file：{}", beforeTrueLength, name);
                return 16;
            }

        } else if (sourceBufferLength < 16) {
            // 当前段为最后一段
            // 处理之前段
            System.arraycopy(beforeBuffer, 0, temp, 0, 16);
            InnerSM4Stream.sm4_one_round(SM4_CONTEXT_DECRYPT.sk, beforeBuffer, out);
            for (int i = 0; i < 16; i++) {
                destBuffer[i] = ((byte) (out[i] ^ iv[i]));
            }
            System.arraycopy(temp, 0, iv, 0, 16);
            // 保存当前段
            System.arraycopy(sourceBuffer, 0, beforeBuffer, 0, sourceBufferLength);
            beforeLength = sourceBufferLength;
            // 本轮读取完毕，但是不够16位，将读取部分的后续置为0
            for (int i = 16 - beforeLength; i < 16; i++) {
                beforeBuffer[i] = 0;
            }
            return 16;
        } else {
//            throw new RuntimeException("文件数据异常，不是有效的SM4加密文件");
//            log.error("（兼容处理，错误已忽略）文件数据异常，不是有效的SM4加密文件：{}s；file：{}", sourceBufferLength, name);
            return 16;
        }
    }

    @Override
    protected void innerOpen() {
        // 第一段
        try {
            beforeLength = in.read(beforeBuffer);
            if (beforeLength != 16) {
                for (int i = 16 - beforeLength; i < 16; i++) {
                    beforeBuffer[i] = 0;
                }
            }
        } catch (Exception e) {
            // 异常，对象创建失败，优先回收已经申请的buffer
            throw new RuntimeException(e.getMessage(), e);
        }

        System.arraycopy(SM4_CONTEXT_DECRYPT.ivBytes, 0, iv, 0, 16);
    }
}
